﻿using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace EffortsTracker
{
    public partial class TrackerUserControl : UserControl, SessionStatusInterface
    {
        TrackerView trackerView;
        private const int WH_KEYBOARD_LL = 13;
        private const int WM_KEYDOWN = 0x0100;
        private const int WM_SYSKEYDOWN = 0x0104;
        private static LowLevelKeyboardProc _proc = HookCallback;
        private static IntPtr _hookID = IntPtr.Zero;

        private static LowLevelMouseProc _proc1 = HookCallback1;
        private static IntPtr _hookID1 = IntPtr.Zero;

        private static TrackerUserControl trackerUserControl;

        SessionController sessionController;

        public TrackerUserControl(TrackerView trackerView, Project project)
        {
            this.trackerView = trackerView;
            InitializeComponent();
            trackerView.Height = this.Height + 25;
            trackerView.Width = this.Width;
            sessionController = new SessionController(this, project);
        }

        public TrackerUserControl(TrackerView trackerView, Session session)
        {
            InitializeComponent();
            sessionController = new SessionController(this, session);
        }

        private void TrackerUserControl_Load(object sender, EventArgs e)
        {
            trackerUserControl = this;
            startStopButton.Focus();
            /*_hookID = SetHook(_proc);
            _hookID1 = SetHook(_proc1);*/
            //Application.Run();
            /*UnhookWindowsHookEx(_hookID);
            UnhookWindowsHookEx(_hookID1);*/
        }

        private void startStopButton_Click(object sender, EventArgs e)
        {
            if (sessionController.running)
            {
                UnhookWindowsHookEx(_hookID);
                UnhookWindowsHookEx(_hookID1);
                startStopButton.Text = "Start";
                sessionController.stopAndSave();
                endTimeTextBox.Text = sessionController.finishDate.ToString();
            }
            else
            {
                clearForm();
                _hookID = SetHook(_proc);
                _hookID1 = SetHook(_proc1);
                sessionController.start();
                startStopButton.Text = "Stop";
                startTimeTextBox.Text = sessionController.startDate.ToString();
                endTimeTextBox.Text = "";
            }
        }

        /*private void stopSaveButton_Click(object sender, EventArgs e)
        {
            sessionController.stopAndSave();
            clearForm();
        }*/

        private void clearForm()
        {
            startStopButton.Text = "Start";
            startTimeTextBox.Text = "";
            endTimeTextBox.Text = "";
            totalDurationTextBox.Text = "0";
            numKeysTextBox.Text = "0";
            mouseClicksTextBox.Text = "0";
        }

        public void updateNumKeys(int numKeys)
        {
            numKeysTextBox.Text = numKeys + "";
        }
        public void updateNumMouseClicks(int numMouseClicks)
        {
            mouseClicksTextBox.Text = numMouseClicks + "";
        }
        public void updateTimeSpan(double totalTime)
        {
            totalDurationTextBox.Text = totalTime + "";
        }


        /** Keyboard handling events */
        private static IntPtr SetHook(LowLevelKeyboardProc proc)
        {
            using (Process curProcess = Process.GetCurrentProcess())
            using (ProcessModule curModule = curProcess.MainModule)
            {
                return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
                    GetModuleHandle(curModule.ModuleName), 0);
            }
        }

        private delegate IntPtr LowLevelKeyboardProc(
            int nCode, IntPtr wParam, IntPtr lParam);

        private static IntPtr HookCallback(
            int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (trackerUserControl.sessionController.running && nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)// || wParam == (IntPtr)WM_SYSKEYDOWN))
            {
                int vkCode = Marshal.ReadInt32(lParam);
                trackerUserControl.sessionController.incrementKeyNum();
                //form1.numKeysTextBox.Text += "Key pressed: " + (Keys)vkCode + "\r\n";
                //Console.WriteLine((Keys)vkCode);
            }
            return CallNextHookEx(_hookID, nCode, wParam, lParam);
        }

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr SetWindowsHookEx(int idHook,
            LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool UnhookWindowsHookEx(IntPtr hhk);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
            IntPtr wParam, IntPtr lParam);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr GetModuleHandle(string lpModuleName);


        /** Mouse events */
        private static IntPtr SetHook(LowLevelMouseProc proc)
        {
            using (Process curProcess = Process.GetCurrentProcess())
            using (ProcessModule curModule = curProcess.MainModule)
            {
                return SetWindowsHookEx(WH_MOUSE_LL, proc,
                    GetModuleHandle(curModule.ModuleName), 0);
            }
        }

        private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);

        private static IntPtr HookCallback1(
            int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (trackerUserControl.sessionController.running && nCode >= 0 && MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam)
            {
                MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
                //Console.WriteLine(hookStruct.pt.x + ", " + hookStruct.pt.y);
                trackerUserControl.sessionController.incrementMouseClicks();
            }
            return CallNextHookEx(_hookID, nCode, wParam, lParam);
        }

        private const int WH_MOUSE_LL = 14;

        private enum MouseMessages
        {
            WM_LBUTTONDOWN = 0x0201,
            WM_LBUTTONUP = 0x0202,
            WM_MOUSEMOVE = 0x0200,
            WM_MOUSEWHEEL = 0x020A,
            WM_RBUTTONDOWN = 0x0204,
            WM_RBUTTONUP = 0x0205
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct POINT
        {
            public int x;
            public int y;
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct MSLLHOOKSTRUCT
        {
            public POINT pt;
            public uint mouseData;
            public uint flags;
            public uint time;
            public IntPtr dwExtraInfo;
        }

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr SetWindowsHookEx(int idHook,
            LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId);

        /*
        private void captureScreenButton_Click(object sender, EventArgs e)
        {
            Rectangle bounds = Screen.GetBounds(Screen.GetBounds(Point.Empty));
            string extension = ".png";
            string ScreenPath = "image.png";

            if (ScreenPath != "")
            {
                extension = new FileInfo(ScreenPath).Extension;
            }
            Size curSize = new Size();
            Point curPos = new Point();
            ScreenCaptureController.CaptureImage(false, curSize, curPos,
                Point.Empty, Point.Empty, bounds, ScreenPath, extension);
        }*/

        //[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        //[return: MarshalAs(UnmanagedType.Bool)]
        //private static extern bool UnhookWindowsHookEx(IntPtr hhk);

        //[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        // private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
        //    IntPtr wParam, IntPtr lParam);

        //[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        //private static extern IntPtr GetModuleHandle(string lpModuleName);
    }
}
